package de.preamp.clients.java.utils;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.net.MalformedURLException;
import java.net.URL;

/**
 * An implementation of {@link AbstractPreferences} that saves the preferences
 * as a serialized object in a local file.
 * 
 * @author André Stannek
 * @version 2010-03-22
 */
public final class PreferencesInFile extends AbstractPreferences implements
	Serializable
{
    /**
     * Generated UID.
     */
    private static final transient long serialVersionUID = -826022923456039926L;

    /**
     * 
     */
    private String serverURL;

    /**
     * 
     */
    private String serverUser;

    /**
     * 
     */
    private char[] serverPassword;

    /**
     * 
     */
    private String lastfmUser;

    /**
     * 
     */
    private char[] lastfmPassword;

    /**
     * 
     */
    private boolean scrobblingEnabled;

    /**
     * 
     */
    private boolean lafEnabled; // NOPMD

    /**
     * 
     */
    private String downloadPath;

    /**
     * the cacheSize in Byte.
     */
    private int cacheSize;

    /**
     * 
     */
    private static final transient String CONFIG_FILE = "config";

    /**
     * Singleton instance.
     */
    private static transient AbstractPreferences prefsInstance = null;

    /**
     * Private Constructor to mask default Constructor.
     */
    private PreferencesInFile()
    {
	super();
	serverURL = "http://preamp.your.domain";
	serverUser = "";
	serverPassword = new char[0];
	lastfmPassword = new char[0];
	lastfmUser = "";
	cacheSize = 10000;
    }

    /**
     * @return a {@link PreferencesInFile} object with the information from the
     *         saved preferences file
     * @throws IOException
     *             on IO error (e.g. if the preferences file wasn't found)
     * @throws ClassNotFoundException
     *             if preferences file doesn't contains a valid
     *             {@link PreferencesInFile} object
     */
    private static AbstractPreferences load() throws IOException,
	    ClassNotFoundException
    {
	final ObjectInputStream objectIS =
		new ObjectInputStream(new FileInputStream(CONFIG_FILE));
	final Object input = objectIS.readObject();
	final AbstractPreferences prefs = (AbstractPreferences) input;
	objectIS.close();
	return prefs;
    }

    /**
     * @throws IOException
     *             if preferences file could not be saved
     */
    private void save() throws IOException
    {
	final ObjectOutputStream objectOS =
		new ObjectOutputStream(new FileOutputStream(CONFIG_FILE));
	objectOS.writeObject(this);
	objectOS.close();
    }

    /**
     * @return an {@link AbstractPreferences} object holding the current
     *         preferences used
     * @see AbstractPreferences#instance()
     */
    public static AbstractPreferences instance()
    {
	final Object lock = new Object();
	synchronized (lock)
	{
	    if (prefsInstance == null)
	    {
		try
		{
		    prefsInstance = load();
		}
		catch (final IOException e)
		{
		    prefsInstance = new PreferencesInFile();
		}
		catch (final ClassNotFoundException e)
		{
		    prefsInstance = new PreferencesInFile();
		}
	    }
	}

	return prefsInstance;
    }

    @Override
    public String getLastfmUser()
    {
	return lastfmUser;
    }

    @Override
    public void setLastfmUser(final String lastfmUser) throws IOException
    {
	this.lastfmUser = lastfmUser;
	save();
    }

    @Override
    public char[] getLastfmPassword()
    {
	return lastfmPassword.clone();
    }

    @Override
    public void setLastfmPassword(final char[] lastfmPassword)
	    throws IOException
    {
	this.lastfmPassword = lastfmPassword.clone();
	save();
    }

    @Override
    public boolean isScrobblingEnabled()
    {
	return scrobblingEnabled;
    }

    @Override
    public void setScrobblingEnabled(final boolean scrobblingEnabled)
    {
	this.scrobblingEnabled = scrobblingEnabled;
    }

    @Override
    public String getServerURL()
    {
	return serverURL;
    }

    @Override
    public void setServerURL(final String serverURL) throws IOException
    {
	new URL(serverURL);
	this.serverURL = serverURL;
	save();
    }

    @Override
    public String getServerUser()
    {
	return serverUser;
    }

    @Override
    public void setServerUser(final String serverUser) throws IOException
    {
	this.serverUser = serverUser;
	save();
    }

    @Override
    public char[] getServerPassword()
    {
	return serverPassword.clone();
    }

    @Override
    public void setServerPassword(final char[] serverPassword)
	    throws IOException
    {
	this.serverPassword = serverPassword.clone();
	save();
    }

    @Override
    public String getDownloadPath()
    {
	return downloadPath;
    }

    @Override
    public void setDownloadPath(final String downloadPath)
    {
	this.downloadPath = downloadPath;
    }

    @Override
    public boolean isConfigured()
    {
	final boolean lastfm =
		!scrobblingEnabled
			|| (lastfmPassword.length > 0 && lastfmUser.length() > 0);
	boolean server = serverUser.length() > 0 && serverPassword.length > 0;
	try
	{
	    new URL(serverURL);
	}
	catch (final MalformedURLException e)
	{
	    server = false;
	}
	return lastfm && server;
    }

    @Override
    public int getCacheSize()
    {
	return cacheSize / 1000;
    }

    @Override
    public void setCacheSize(final int cacheSize)
    {
	if (cacheSize < 100)
	{
	    this.cacheSize = 100000;
	}
	else
	{
	    this.cacheSize = cacheSize * 1000;
	}

    }

    @Override
    public boolean isSystemLAFEnabled()
    {
	return lafEnabled;
    }

    @Override
    public void setSystemLAFEnabled(final boolean lafEnabled)
    {
	this.lafEnabled = lafEnabled;

    }
}
